package xstring

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

func ABool(c any) bool {
	switch s := c.(type) {
	case float64, float32, *float64, *float32:
		return s != 0
	case int, uint, int32, uint32, int8, uint8, int16, uint16, int64, uint64,
		*int, *uint, *int32, *uint32, *int8, *uint8, *int16, *uint16, *int64, *uint64,
		time.Duration, *time.Duration:
		return s != 0
	case bool:
		return s
	case *bool:
		return *s
	case string:
		temp := strings.ToLower(s)
		return temp != "" && temp != "false" && temp != "0"
	case *string:
		temp := strings.ToLower(*s)
		return temp != "" && temp != "false" && temp != "0"
	}
	return false
}

// Any类型变量转为String类型变量
//
//	c	待转换的变量
func AString(c any) string {
	switch s := c.(type) {
	case string:
		return s
	case int, uint, int32, uint32, int8, uint8, int16, uint16, int64, uint64, time.Duration, *time.Duration:
		return fmt.Sprintf("%v", s)
	case *int, *uint, *int32, *uint32, *int8, *uint8, *int16, *uint16, *int64, *uint64, *float32, *float64:
		return fmt.Sprintf("%#v", s)
	case time.Time:
		return s.Format(time.DateTime)
	case *time.Time:
		return s.Format(time.DateTime)
	case float32, float64:
		return fmt.Sprintf("%g", c)
	case json.Number:
		return s.String()
	case *json.Number:
		return s.String()
	case *bool:
		if *s {
			return "true"
		}
		return "false"
	case bool:
		if s {
			return "true"
		}
		return "false"
	}
	return ""
}

// 结构体转换【通过json进行转换，所以建立结构体时请注意json对应】
//
//	old	待转换的变量类型
//	new	转换后的变量存储位置【此值需要为指针】
func Any2any(old, new any) error {
	// old转[]byte
	b, err := json.Marshal(old)
	if err != nil {
		return err
	}
	return json.Unmarshal(b, new)
}

// 强制断言成int类型（不考虑效率的情况下可以这么使用）
//
//	a	任意类型变量
func Any2Int(a any) int {
	return int(Any2Integer(a))
}

// 强制断言成uint类型
//
//	a	任意类型变量
func Any2UInt(a any) uint {
	return uint(Any2Integer(a))
}

// 强制断言成int8类型
//
//	a	任意类型变量
func Any2Int8(a any) int8 {
	return int8(Any2Integer(a))
}

// 强制断言成uint8类型
//
//	a	任意类型变量
func Any2Uint8(a any) uint8 {
	return uint8(Any2Integer(a))
}

// 强制断言成int16类型
//
//	a	任意类型变量
func Any2Int16(a any) int16 {
	return int16(Any2Integer(a))
}

// 强制断言成uint16类型
//
//	a	任意类型变量
func Any2Uint16(a any) uint16 {
	return uint16(Any2Integer(a))
}

// 强制断言成int32类型
//
//	a	任意类型变量
func Any2Int32(a any) int32 {
	return int32(Any2Integer(a))
}

// 强制断言成uint32类型
//
//	a	任意类型变量
func Any2Uint32(a any) uint32 {
	return uint32(Any2Integer(a))
}

// 强制断言成uint64类型
//
//	a	任意类型变量
func Any2Uint64(a any) uint64 {
	// 此处多判断一步，尽量避免容量丢失
	if v, ok := a.(uint64); ok {
		return v
	}
	return uint64(Any2Integer(a))
}

// 断言任意变量的类型
//
//	a	任意类型变量
//
// returns: 0~99，
// 0~9为大类，若仅需要判断大类的话可直接使用 <return> % 10
// 10~99为子分类，如：1为整形 31为字符串类型的整形 21为浮点类型的整形，若需要获取显示类型可使用 <return> == 3 || <return> / 10 == 3 来进行获取
//
//	0	未知类型
//	1	整形
//	11	布尔类型（因此值可视为特殊类型整形，所以归类到整形中）
//	2	浮点型
//	3	字符串型
//	31	字符串类型的整形
//	32	字符串类型的浮点型
//	4	json.Number类型
//	5	time.Time类型
//	6	time.Duration类型
//	7	error类型
func Any2ype(a any) uint8 {
	switch b := a.(type) {
	case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
		return 1
	case bool:
		return 11
	case float32, float64:
		return 2
	case string:
		if CheckNumber(b) {
			return 31
		} else if CheckFloat(b) {
			return 32
		}
		return 3
	case json.Number, *json.Number:
		return 4
	case time.Time, *time.Time:
		return 5
	case time.Duration, *time.Duration:
		return 6
	case error:
		return 7
	}
	return 0
}

// 判断该类型是否为整数
//
//	a	待判断的浮点数
func IsInteger(a float64) bool {
	// %g会自动判断浮点数的小数位精度，来自动识别要不要显示.xxx
	return !strings.Contains(fmt.Sprintf("%g", a), ".")
}

// 任意类型断言成浮点型
// PS: 会将整形变量也改变类型成浮点型，建议先确定好类型再行确定是否使用
// 经测试，类型断言的效率要比反射稍高，所以此处使用类型断言进行any类型转换
//
//	a	任意类型变量值
func Any2Float(a any) float64 {
	switch b := a.(type) {
	case float64:
		return b
	case *float64:
		return *b
	case float32:
		return float64(b)
	case *float32:
		return float64(*b)
	case int, uint, int32, uint32, int8, uint8, int16, uint16, int64, uint64, *int, *uint, *int32, *uint32, *int8, *uint8, *int16, *uint16, *int64, *uint64:
		return float64(Any2Integer(a))
	case string:
		if CheckFloat(b) {
			return ToFloat64(b)
		}
	case bool:
		if b {
			return 1
		}
	case *bool:
		if *b {
			return 1
		}
	}
	return 0
}

// 任意类型断言成整形
// PS: 浮点数会舍弃精度转换，所以建议先确定好不是浮点数、字符串等类型以后再进行转换
// 经测试，类型断言的效率要比反射稍高，所以此处使用类型断言进行any类型转换
//
//	a	任意类型变量值
func Any2Integer(a any) int64 {
	switch b := a.(type) {
	case int:
		return int64(b)
	case uint:
		return int64(b)
	case int8:
		return int64(b)
	case uint8:
		return int64(b)
	case int16:
		return int64(b)
	case uint16:
		return int64(b)
	case int32:
		return int64(b)
	case uint32:
		return int64(b)
	case int64:
		return b
	case uint64:
		return int64(b)
	case *int:
		return int64(*b)
	case *uint:
		return int64(*b)
	case *int8:
		return int64(*b)
	case *uint8:
		return int64(*b)
	case *int16:
		return int64(*b)
	case *uint16:
		return int64(*b)
	case *int32:
		return int64(*b)
	case *uint32:
		return int64(*b)
	case *int64:
		return *b
	case *uint64:
		return int64(*b)
	case float32:
		return int64(b)
	case float64:
		return int64(b)
	case *float32:
		return int64(*b)
	case *float64:
		return int64(*b)
	case string:
		if CheckFloat(b) {
			return ToInt64(b)
		}
	case bool:
		if b {
			return 1
		}
	case *bool:
		if *b {
			return 1
		}
	}
	return 0
}
